
export default class Reflect {

  public static data: Map<any, any> = new Map();

  public static getValue<T>(instanse: any, paths: string[], defaultValue?: T): T {
    let record = this.data.get(instanse);
    if (!record) {
      return defaultValue as T;
    }
    for (const path of paths.slice(0, -1)) {
      record = record[path];
      if (!record) {
        return defaultValue as T;
      }
    }
    const lastPath = paths[paths.length - 1];
    return record[lastPath] || defaultValue;
  }

  public static getRecordCreatePath(instanse: any, paths: string[]) {
    if (!this.data.has(instanse)) {
      this.data.set(instanse, {});
    }
    let record = this.data.get(instanse);
    for (const path of paths.slice(0, -1)) {
      if (!record[path]) {
        record[path] = {};
      }
      record = record[path];
    }
    return record;
  }

  public static setValue(instanse: any, paths: string[], value: any) {
    const record = this.getRecordCreatePath(instanse, paths);
    const lastPath = paths[paths.length - 1];
    record[lastPath] = value;
  }

  public static pushValue(instanse: any, paths: string[], value: any, defaultValue: any[] = []) {
    const record = this.getRecordCreatePath(instanse, paths);
    const lastPath = paths[paths.length - 1];
    if (!record[lastPath]) {
      record[lastPath] = defaultValue;
    }
    record[lastPath].push(value);
  }

  public static addValue(instanse: any, paths: string[], defaultValue: number = 0): number {
    const record = this.getRecordCreatePath(instanse, paths);
    const lastPath = paths[paths.length - 1];
    if (!record[lastPath]) {
      record[lastPath] = defaultValue;
    }
    record[lastPath] += 1;
    return record[lastPath];
  }

  public static reduceValue(instanse: any, paths: string[], defaultValue: number = 0): number {
    const record = this.getRecordCreatePath(instanse, paths);
    const lastPath = paths[paths.length - 1];
    if (!record[lastPath]) {
      record[lastPath] = defaultValue;
    }
    record[lastPath] -= 1;
    return record[lastPath];
  }

  public static clear(instanse: any) {
    this.data.delete(instanse);
  }

  public static forEachValue<T>(instanse: any, paths: string[], defaultValue: T[], forEachFunc: (item: T, index: number, array: T[]) => void): void {
    const values = this.getValue(instanse, paths, defaultValue);
    values.forEach(forEachFunc);
  }

}
